package com.xuecheng.search.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.xuecheng.framework.domain.course.CoursePub;
import com.xuecheng.framework.domain.course.TeachplanMediaPub;
import com.xuecheng.framework.domain.search.CourseSearchParam;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;

@Service
public class SearchService {
    
    //读取配置文件信息
    @Value("${xuecheng.course.index}")
    private String index;
    
    @Value("${xuecheng.course.type}")
    private String type;
     
    @Value("${xuecheng.course.source_field}")
    private String source_field;
    
    @Value("${xuecheng.media.index}")
    private String media_index;
    
    @Value("${xuecheng.media.type}")
    private String media_type;
    
    @Value("${xuecheng.media.source_field}")
    private String media_source_field;
    
    @Autowired
    RestHighLevelClient restHighLevelClient;
    
    //课程搜索
    public QueryResponseResult<CoursePub> list(int page, int size, CourseSearchParam courseSearchParam) {
        if(courseSearchParam == null) {
            courseSearchParam = new CourseSearchParam();
        }
        //创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(index);
        //设置类型
        searchRequest.types(type);
        //构建搜索源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //过滤源字段
        String [] source_fields = source_field.split(",");
        searchSourceBuilder.fetchSource(source_fields,new String[] {});
        //创建布尔查询对象
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //设置搜索条件，根据关键字搜索，使用multiMatchQuery
        if(StringUtils.isNotEmpty(courseSearchParam.getKeyword())) {
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders
                    .multiMatchQuery(courseSearchParam.getKeyword(), "name","description","teachplan")
                     .minimumShouldMatch("70%")
                     .field("name", 10);
            //组装到布尔查询汇总
            boolQueryBuilder.must(multiMatchQueryBuilder);
        }
        //按照一级分类查询，使用filter过滤
        if(StringUtils.isNotEmpty(courseSearchParam.getMt())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("mt", courseSearchParam.getMt()));
        }
        //按照二级分类查询
        if(StringUtils.isNotEmpty(courseSearchParam.getSt())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("st", courseSearchParam.getSt()));
        }
        //按照难度等级查询
        if(StringUtils.isNotEmpty(courseSearchParam.getGrade())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("grade", courseSearchParam.getGrade()));
        }
        //分页设置
        if(page<=0) {
            page = 1;
        }
        if(size<=0) {
            size = 20;
        }
        int start = (page-1)*size;//开始
        searchSourceBuilder.from(start);
        searchSourceBuilder.size(size);
        //将布尔查询对象设置到搜索源对象中
        searchSourceBuilder.query(boolQueryBuilder);
        //设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font class='eslight'>");//开始标签
        highlightBuilder.postTags("</font>");//闭合标签
        //设置高亮字段
        highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
        searchSourceBuilder.highlighter(highlightBuilder);
        //将搜索源对象设置到搜索请求对象中
        searchRequest.source(searchSourceBuilder);
        QueryResult<CoursePub> queryResult = new QueryResult<>();
        List<CoursePub> list = new ArrayList<>();
        try {
            //执行搜索，获取搜索响应对象
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest);
            //获取响应结果
            SearchHits hits = searchResponse.getHits();
            //匹配的总记录数
            long totalHits = hits.totalHits;
            queryResult.setTotal(totalHits);
            SearchHit []searchHits = hits.getHits();//获取匹配到的记录
            for(SearchHit hit:searchHits) {//遍历记录
                CoursePub coursePub = new CoursePub();
                //获取源文档
                Map<String,Object> sourceMap = hit.getSourceAsMap();
                //取出ID
                String id = (String) sourceMap.get("id");
                coursePub.setId(id);
                //取出名称
                String name = (String) sourceMap.get("name");
                //取出高亮字段
                Map<String,HighlightField> highlightFields = hit.getHighlightFields();
                if(highlightFields!=null) {
                    HighlightField nameHighlightField = highlightFields.get("name");
                    if(nameHighlightField!=null) {
                        Text []fragments = nameHighlightField.getFragments();
                        StringBuffer sb = new StringBuffer();
                        for(Text t:fragments) {
                            sb.append(t.toString());
                        }
                        //重新给name赋值
                        name = sb.toString();
                    }
                }
                coursePub.setName(name);
                //取出图片
                String pic = (String) sourceMap.get("pic");
                coursePub.setPic(pic);
                //取出新价格
                if(sourceMap.get("price")!=null) {
                    Double price = (Double) sourceMap.get("price");
                    coursePub.setPrice(price);
                }
                //取出旧价格
                if(sourceMap.get("price_old")!=null) {
                    Double price_old = (Double) sourceMap.get("price_old");
                    coursePub.setPrice_old(price_old);
                }
                //将coursePub对象添加到list集合中
                list.add(coursePub);
            }
            //添加到查询结果中
            queryResult.setList(list);
            QueryResponseResult<CoursePub> queryResponseResult = 
                    new QueryResponseResult<CoursePub>(CommonCode.SUCCESS,queryResult);
            return queryResponseResult;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new QueryResponseResult<CoursePub>(CommonCode.FAIL,null);
    }

    //向es请求查询索引信息
    public Map<String, CoursePub> getAll(String id) {
        // 搜索请求对象
        SearchRequest searchRequest = new SearchRequest(index);
        //指定类型
        searchRequest.types(type);
        //搜索源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //使用termQuery精确匹配
        searchSourceBuilder.query(QueryBuilders.termQuery("id", id));
        //将源对象设置到请求对象中
        searchRequest.source(searchSourceBuilder);
        Map<String,CoursePub> map = new HashMap<>();
        try {
            //执行搜索，获取搜索响应对象
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest);
            SearchHits hits = searchResponse.getHits();
            SearchHit [] searchHits = hits.getHits();
            for(SearchHit hit:searchHits) {//遍历，只会取出一条记录
                CoursePub coursePub = new CoursePub();
                //获取源文档内容
                Map<String,Object> sourceMap = hit.getSourceAsMap();
                //取出字段信息，设置到对象中
                String courseId = (String) sourceMap.get("id");
                coursePub.setId(courseId);
                String name = (String) sourceMap.get("name");
                coursePub.setName(name);
                String grade = (String) sourceMap.get("grade");
                coursePub.setGrade(grade);
                String charge = (String) sourceMap.get("charge");
                coursePub.setCharge(charge);
                String pic = (String) sourceMap.get("pic");
                coursePub.setPic(pic);
                String description = (String) sourceMap.get("description");
                coursePub.setDescription(description);
                String teachplan = (String) sourceMap.get("teachplan");
                coursePub.setTeachplan(teachplan);
                map.put(courseId, coursePub);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    //根据多个课程id查询课程媒资信息
    public QueryResponseResult<TeachplanMediaPub> getMedia(String[] teachplanIds) {
        // 搜索请求对象
        SearchRequest searchRequest = new SearchRequest(media_index);
        //类型
        searchRequest.types(media_type);
        //构建搜索源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //根据多个id查询
        searchSourceBuilder.query(QueryBuilders.termsQuery("teachplan_id", teachplanIds));
        //过滤源字段
        String []includes = media_source_field.split(",");
        searchSourceBuilder.fetchSource(includes,new String[] {});
        //源对象放入请求对象中
        searchRequest.source(searchSourceBuilder);
        List<TeachplanMediaPub> list = new ArrayList<>();
        long total = 0;
        try {
            //执行搜索，获取搜索请求对象
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest);
            SearchHits searchHits = searchResponse.getHits();
            total = searchHits.totalHits;
            SearchHit []hits = searchHits.getHits();
            for(SearchHit hit:hits) {
                TeachplanMediaPub teachplanMediaPub = new TeachplanMediaPub();
                //获取源文档内容
                Map<String,Object> sourceMap = hit.getSourceAsMap();
                //取出字段
                String courseId = (String) sourceMap.get("courseid");
                String mediaId = (String) sourceMap.get("media_id");
                String teachplanId = (String) sourceMap.get("teachplan_id");
                String mediaUrl = (String) sourceMap.get("media_url");
                String mediaName = (String) sourceMap.get("media_fileoriginalname");
                teachplanMediaPub.setCourseId(courseId);
                teachplanMediaPub.setMediaId(mediaId);
                teachplanMediaPub.setTeachplanId(teachplanId);
                teachplanMediaPub.setMediaUrl(mediaUrl);
                teachplanMediaPub.setMediaFileOriginalName(mediaName);
                //添加进list
                list.add(teachplanMediaPub);
            } 
        } catch (Exception e) {
            e.printStackTrace();
        }
        QueryResult<TeachplanMediaPub> queryResult = new QueryResult<>();
        queryResult.setTotal(total);
        queryResult.setList(list);
        QueryResponseResult<TeachplanMediaPub> queryResponseResult = new 
                QueryResponseResult<>(CommonCode.SUCCESS, queryResult);
        return queryResponseResult;
    }

}
